mod palette;

use std::{
    fmt::{self, Debug},
    ops,
};

pub trait Location {
    fn locate(&self, extent: &Extent) -> Option<usize>;
}

#[derive(Debug, Clone, Copy)]
pub enum Extent {
    Linear(usize),
    Planar(usize, usize),
    Spatial(usize, usize, usize),
}

impl Extent {
    #[inline]
    pub fn get_indices_count(&self) -> usize {
        match self {
            Extent::Linear(length) => *length,
            Extent::Planar(width, height) => width * height,
            Extent::Spatial(width, height, length) => width * height * length,
        }
    }
}

#[derive(Debug)]
pub struct Palette<T: PartialEq> {
    entries: Vec<RcEntry<T>>,
    indices: Vec<Option<usize>>,
    extent: Extent,
}

#[derive(Clone, Copy)]
struct RcEntry<T: PartialEq> {
    t: T,
    rc: isize,
}


impl<T: PartialEq> RcEntry<T> {
    #[inline]
    fn new(t: T) -> Self {
        Self { t, rc: 0 }
    }

    #[inline]
    fn add_ref(&mut self) {
        self.rc += 1;
    }

    #[inline]
    fn release(&mut self) {
        self.rc -= 1;
    }

    #[inline]
    fn is_recyclable(&self) -> bool {
        self.rc <= 0
    }
}

impl<T: PartialEq> ops::Deref for RcEntry<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.t
    }
}

impl<T: PartialEq + Debug> fmt::Debug for RcEntry<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "<{:?},{}>", &self.t, self.rc)
    }
}